All files / src/app/api/dev/tickets/[id]/restore route.ts

0% Statements 0/88
100% Branches 0/0
0% Functions 0/1
0% Lines 0/88

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89                                                                                                                                                                                 
export const dynamic = "force-dynamic";

/**
 * Dev Ticket Restore API
 * POST /api/dev/tickets/[id]/restore - Restore a soft-deleted ticket
 */

import { NextRequest, NextResponse } from 'next/server';
import { Session } from "next-auth";
import {
  withAdmin,
  withErrorHandling,
  successResponse,
  ApiError,
  ApiSuccessResponse,
  ApiErrorResponse } from "@/lib/api";
import { RouteContext } from "@/lib/api/middleware";
import type { AuthenticatedUser } from '@/lib/api/middleware/types';
import { prisma } from '@/lib/prisma';
import { createTicketHistory, updateParentChildCounts } from '@/lib/dev-ticket';
import { logger } from '@/lib/logging';

interface RouteParams {
  params: Promise<{ id: string }>;
}

async function handlePost(
  request: NextRequest,
  context: RouteContext | undefined,
  session: Session,
  user: AuthenticatedUser
): Promise<NextResponse<ApiSuccessResponse<unknown> | ApiErrorResponse>> {
  const { id } = await (context as RouteParams).params;

  // Check if ticket exists
  const ticket = await prisma.devTicket.findUnique({
    where: { id },
    select: {
      id: true,
      ticketNumber: true,
      parentId: true,
      deletedAt: true}});

  if (!ticket) {
    throw ApiError.notFound('Ticket not found');
  }

  if (!ticket.deletedAt) {
    throw ApiError.badRequest('Ticket is not deleted');
  }

  // Check if parent exists and is not deleted
  if (ticket.parentId) {
    const parent = await prisma.devTicket.findUnique({
      where: { id: ticket.parentId },
      select: { deletedAt: true, ticketNumber: true }});
    if (parent?.deletedAt) {
      throw ApiError.badRequest(
        `Cannot restore ticket: parent ticket ${parent.ticketNumber} is also deleted. Restore the parent first.`
      );
    }
  }

  // Restore the ticket
  await prisma.devTicket.update({
    where: { id },
    data: {
      deletedAt: null,
      deletedById: null}});

  // Record in history
  await createTicketHistory(id, user.id, 'restored');

  // Update parent's child count if applicable
  if (ticket.parentId) {
    await updateParentChildCounts(ticket.parentId);
  }

  logger.info(`Restored ticket ${ticket.ticketNumber}`, {
    category: 'DEV_TICKETS',
    ticketId: id,
    userId: user.id});

  return successResponse({
    message: 'Ticket restored successfully'});
}

export const POST = withErrorHandling(withAdmin(handlePost));